<template>
  <div class="container">
    <vue-tree :collapseEnabled="false" :config="treeConfig" :dataset="data"
              linkStyle="straight" style="width: 800px; height: 600px; border: 1px solid gray;">
      <template v-slot:node="{ node, collapsed }">
        <div :style="{ border: collapsed ? '2px solid grey' : '' }" class="rich-media-node"
             @click="handleClickNode(node)">
          <span style="padding: 4px 0; font-weight: bold;">
            {{ node.name }}
          </span>
          <span v-if="node.parentId !== 0" style="padding:4px 0;font-weight: bold;">
            {{ node.weight && node.weight * 100 + '%' }}
          </span>
        </div>
      </template>
    </vue-tree>

    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>当前节点</span>
      </div>
      <el-form ref="formRef" :model="currentNode" label-position='left' label-width="100px">
        <el-form-item label="节点ID" prop="name">
          <el-tag>{{ currentNode.id }}</el-tag>
        </el-form-item>
        <el-form-item label="父节点ID" prop="parentId">
          <el-tag>{{ currentNode.parentId }}</el-tag>
        </el-form-item>
        <el-form-item label="名称" prop="name">
          <el-input v-model="currentNode.name"></el-input>
        </el-form-item>
        <el-form-item v-if="currentNode.parentId !== 0" label="权重" prop="weight">
          <el-input v-model="currentNode.weight"></el-input>
        </el-form-item>
        <el-form-item v-if="!currentNode.leaf" label="算子信息">
        </el-form-item>
        <el-divider v-if="currentNode.operator !== null" border-style="dashed"/>
        <el-form-item v-if="currentNode.operator!==null && currentNode.operator.operatorName!==null"
                      label="算子名称"
                      prop="operatorName">
          <el-tag>
            {{ currentNode.operator !== null ? currentNode.operator.operatorName : "" }}
          </el-tag>
        </el-form-item>
        <el-form-item v-if="currentNode.operator !== null && currentNode.operator.operatorBody!==null"
                      label="算子主体"
                      prop="operator.operatorBody">
          <el-tag>
            {{ currentNode.operator !== null ? currentNode.operator.operatorBody : "" }}
          </el-tag>
        </el-form-item>
      </el-form>

      <div class="operate">
        <el-button type="danger" @click="deleteNode">
          删除
        </el-button>
        <el-button v-if="!currentNode.leaf" type="warning" @click="startOperatorAllocator">
          修改算子
        </el-button>
        <el-button type="warning" @click="startInsertNode">
          新增子结点
        </el-button>
        <el-button type="primary" @click="modify">
          提交修改
        </el-button>
      </div>
    </el-card>

    <el-dialog
        id="operatorAllocatorDialog"
        :visible.sync="operatorAllocatorDialogVisible"
        title="为结点分配算子"
        width="50%"
        @close="endOperatorAllocator"
    >
      <!--        分配算子的对话框-->
      <el-form
          ref="ruleFormRef"
          label-position='left'
          label-width="100px"
      >
        <el-form-item label="目标结点编号" prop="currentNode.id">
          <el-input v-model="currentNode.id" disabled></el-input>
        </el-form-item>
        <el-form-item label="目标结点名称" prop="currentNode.name">
          <el-input v-model="currentNode.name" disabled></el-input>
        </el-form-item>
        <el-form-item label="目标算子名称">
          <el-select ref="operatorSelected" v-model="allOperators.operatorName"
                     filterable
                     placeholder="请选择一个算子"
          >
            <el-option v-for="{id,operatorName,operatorNum} in allOperators"
                       :key="id"
                       :disabled="operatorNum!==currentNode.children.length"
                       :label="operatorName"
                       :value="id">

            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="endOperatorAllocator">取消</el-button>
        <el-button type="primary"
                   @click="allocateOperator">
          确定
        </el-button>
      </span>
    </el-dialog>

    <el-dialog
        id="insertNodeDialog"
        :visible.sync="insertNodeDialogVisible"
        title="新增子结点"
        width="50%"
        @close="endInsertNode">
      <el-form
          ref="ruleFormRef"
          :model="nodeToInsert"
          :rules="insertNodeRules"
          label-position='left'
          label-width="100px"
      >
        <!--        新增结点的表单-->
        <el-form-item label="父结点编号" prop="parentId">
          <el-input v-model="currentNode.id" disabled></el-input>
        </el-form-item>
        <el-form-item label="父结点名称">
          <el-input v-model="currentNode.name" disabled></el-input>
        </el-form-item>
        <el-form-item label="新结点名称" prop="name">
          <el-input v-model="nodeToInsert.name"
                    placeholder="请输入新结点名称" type="text"
          ></el-input>
        </el-form-item>
        <el-form-item label="新结点权重" prop="weight">
          <el-input v-model="nodeToInsert.weight"
                    placeholder="请输入结点权重"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="endInsertNode">取消</el-button>
        <el-button type="primary"
                   @click="insertNode">
          确定
        </el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import {checkWeight, findNodeById} from '../utils'

export default {
  data() {
    /**
     * 自定义校验器
     * 校验权重：范围为0到1
     */
    const validateWeight = (rule, value, callback) => {
      if (value.length === 0) {
        callback(new Error('权重不能为空'));
      } else {
        if (value >= 0 && value <= 1) {
          callback()
        } else {
          callback(new Error('请输入范围在0-1之间的数字'));
        }
      }
    }
    return {
      data: {},
      treeConfig: {nodeWidth: 120, nodeHeight: 80, levelHeight: 200},
      currentIndex: 0,
      currentNode: {},
      origin: {},
      allOperators: [],
      operatorAllocatorDialogVisible: false,//分配算子的界面是否可见
      insertNodeDialogVisible: false,//新增子结点的界面是否可见
      nodeToInsert: {
        weight: 0.0,
        name: "",
        leaf: true,
        parentId: 0,
        rootId: origin.rootId,//这里传结构树的ROOT编号
      },//要插入的结点信息
      insertNodeRules: {
        name: {
          type: "string",
          required: true,
          trigger: "blur",
          message: "新结点名称不能为空"
        },
        weight: [
          {trigger: "blur", validator: validateWeight},
        ]
      }//新增结点的规则
    }
  },
  created() {
    this.getAllOperators();
  },
  // mounted页面渲染完毕
  async mounted() {
    await this.getCurrentTree();
  },
  methods: {
    /**
     * 渲染当前树结构
     * @returns {Promise<ElMessageComponent>}
     */
    async getCurrentTree() {
      const treeId = this.$route.query.treeid
      const res = await this.$http.get(`tree/detail?treeId=${treeId}`)

      if (res.code !== 200) {
        return this.$message.error('获取指标树失败')
      }

      this.origin = {
        id: res.data.id,
        name: res.data.name,
        userId: res.data.userId,
        rootId: res.data.rootId
      }

      this.data = res.data.root
      this.currentNode = res.data.root
      this.nodeToInsert.rootId = this.origin.rootId;
    },
    /**
     * 获取所有的算子
     * @returns {Promise<ElMessageComponent>}
     */
    async getAllOperators() {
      // 动态获取所有算子，也许可以用在远程请求
      const res = await this.$http.get(`/ope/select-allOpe`)
      if (res.code !== 200) {
        return this.$message.error('获取指标树列表失败')
      }
      this.allOperators = res.data;
    },

    async handleClickNode(node) {
      this.currentNode = findNodeById(node.id, this.data)
      this.nodeToInsert.parentId = this.currentNode.id;//这里也动态修改编号
    },

    modify() {
      const isLegal = checkWeight(this.data)
      if (!isLegal) return this.$message.error('权重和不合法！')

      const obj = this.origin
      obj.root = this.data

      this.$http.post('/tree/update', obj)
      this.$message.success("更新成功！")
    },

    /**
     * 为一个指标结点分配算子系列之使界面可见
     */
    startOperatorAllocator() {
      this.operatorAllocatorDialogVisible = true;
    },

    /**
     * 为一个指标结点分配算子系列之隐藏界面
     */
    endOperatorAllocator() {
      this.operatorAllocatorDialogVisible = false;
    },

    /**
     * 为一个指标结点分配算子系列之向后端发送请求
     * @returns {Promise<ElMessageComponent>}
     */
    async allocateOperator() {
      const nodeId = this.currentNode.id;
      const operatorId = this.$refs.operatorSelected.selected.value
      const res = await this.$http.post(`ope/allocate?nodeId=${nodeId}&&operatorId=${operatorId}`);
      if (res.code !== 200) {
        this.endOperatorAllocator();
        return this.$message.error(res.message);
      }
      this.$message.success(res.message);
      await this.getCurrentTree();
      this.endOperatorAllocator();
    },

    /**
     * 开始进行结点新增，这个方法会展示对应窗口。
     */
    startInsertNode() {
      this.insertNodeDialogVisible = true;
      this.nodeToInsert.parentId = this.currentNode.id;
    },

    async insertNode() {
      await this.$refs.ruleFormRef.validate(async (isValid) => {
        if (!isValid) return
        const res = await this.$http.post("/tree-node/insert-one",
            this.nodeToInsert);
        if (res.code !== 200) {
          this.endInsertNode();
          return this.$message.error(res.message);
        }
        this.$message.success(res.message);
        this.endInsertNode();
        await this.getCurrentTree();
      });
    },

    /**
     * 取消or结束结点新增，这个方法将关闭窗口。
     */
    endInsertNode() {
      this.insertNodeDialogVisible = false;
    },
    /**
     * 删除结点
     */
    async deleteNode() {
      const nodeId = this.currentNode.id;
      const result = await this.$http.get(`/tree-node/delete-one?nodeId=${nodeId}`);
      if (result.code !== 200) {
        return this.$message.error(result.message);
      }
      this.$message.success(result.message);
      await this.getCurrentTree();
    }
  },
}
</script>

<style lang="less" scoped>
.container {
  display: flex;
}

.rich-media-node {
  width: 80px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  color: white;
  background-color: #f7c616;
  border-radius: 4px;
}

.box-card {
  width: 500px;
  height: 650px;
}

.operate {
  display: flex;
}
</style>